/// 除了函数签名，结构体在含有引用类型成员的时候也需要标注生命周期参数，
/// 否则编译器会报错: missing lifetime specifier
/// 生命周期省略规则 (Lifetime Elision Rule)，一共包含三条规则
/// 每个输入位置上省略的生命周期都将成为一个不同的生命周期参数。
/// 如果只有一个输入生命周期的位置(不管是否忽略)，则该生命周期都将分配给输出生命周期。
/// 如果存在多个输入生命周期的位置，但是其中包含着&self或&mut self，则self的生命周期都将分配给输出生命周期 。
pub fn start() {
    let foo = Foo { part: "te哈哈st" };
    println!("{:?}", foo);
    let option = foo.get_index_str(2);
    drop(foo); // 这里可以drop，但是不影响option
    println!("{:?}", option);
}

/// 这里的生命周期参数标记，实际上是和编译器约定了一个规则:
/// 结构体实例的生命周期应短于或等于任意一个引用成员的生命周期。
#[derive(Debug)]
struct Foo<'a> {
    part: &'a str,
}

impl<'a> Foo<'a> {
    fn get_index_str(&self, index: usize) -> Option<&'a str> {
        if index >= self.part.len() {
            return None;
        }
        if self.part.is_char_boundary(index) {
            Some(&self.part[index..])
        } else {
            None
        }
    }

    pub fn new(s: &'a str) -> Self {
        Foo {
            part: Foo::split_first(s),
        }
    }

    fn split_first(s: &str) -> &str {
        s.split(',').next().unwrap_or(s)
    }
}
